<?php

namespace Sharks\Core\Persistence\Cache;

use Sharks\Core\AppContext;
use Sharks\Core\Support\Base\Argument;
use Sharks\Core\Support\Cache\FileCache;

/**
 * 通过文件形式的缓存
 */
class DatabaseFileCacheProvider extends DatabaseCacheProvider {

    const TABLE_TAG_DIR = '/database/tag/';

    private $storagePath;
    private $fileCache;

    public function __construct() {
        $this->storagePath = AppContext::instance()->path->storage;
        $this->fileCache = FileCache::instance();
    }

    protected function storeTableTag($table) {
        $table = trim($table, " \t\n\r\0\x0B\"`");
        $file = $this->storagePath . self::TABLE_TAG_DIR . $table . '.php';
        $time = time();
        file_put_contents($file, '<?php return "'. $table . '-' . $time . '";');
        return $time;
    }

    protected function storeTableTags(array $tables) {
        foreach ($tables as $table) {
            $this->storeTableTag($table);
        }
    }

    protected function loadTableTag($table) {
        $table = trim($table, " \t\n\r\0\x0B\"`");
        $file = $this->storagePath . self::TABLE_TAG_DIR . $table . '.php';
        if (file_exists($file)) {
            return require ($file);
        }
        else {
            return $this->storeTableTag($table);
        }
    }

    protected function loadTableTags(array $tables = null) {
        if (Argument::isEmpty($tables)) {
            return "";
        }
        elseif (1 == count($tables)) {
            return $this->loadTableTag($tables[0]);
        }
        else {
            sort($tables);
            $tags = [];
            foreach ($tables as $table) {
                $tags[] = $this->loadTableTag($table);
            }
            return implode('', $tags);
        }
    }

    public function has($sql, array $tables = null) {
        if (Argument::isNotEmpty($tables)) {
            return $this->fileCache->isExisting($sql . $this->loadTableTags($tables));
        }
        else {
            return $this->fileCache->isExisting($sql . $this->loadTableTags($this->getTablesByQuery($sql)));
        }
    }

    public function get($sql, array $tables = null) {
        if (Argument::isNotEmpty($tables)) {
            return $this->fileCache->get($sql . $this->loadTableTags($tables));
        }
        else {
            return $this->fileCache->get($sql . $this->loadTableTags($this->getTablesByQuery($sql)));
        }
    }

    public function put($sql, $cacheableValue, array $tables = null) {

        if (Argument::isNotEmpty($tables)) {
            $this->fileCache->set($sql . $this->loadTableTags($tables), $cacheableValue, 600); // 600s is 10m
        }
        else {
            $this->fileCache->set($sql . $this->loadTableTags($this->getTablesByQuery($sql)), $cacheableValue, 600);// 600s is 10m
        }
        return $cacheableValue;
    }

    public function changeByQuery($sql) {
        $this->storeTableTags($this->getTablesByQuery($sql));
    }

    public function change($table) {
        return $this->storeTableTag($table);
    }

    public function changes(array $tables) {
        $this->storeTableTags($tables);
    }
}